//
// Created by yonghu0 on 25-10-20.
//

#include "ProblemList.h"
#include "MongoDataBase.h"
#include <string>
#include <fstream>

#include "../include/httplib.h"
#include "RedisDataBase.h"

const std::string PROBLEMDATAPATH = "../../problemdata/";

ProblemList::ProblemList()
{
}

ProblemList::~ProblemList()
{
}

ProblemList *ProblemList::GetInstance()
{
    static ProblemList problemlist;
    return &problemlist;
}

Json::Value ProblemList::SelectProblem(Json::Value queryjson)
{
    std::string problemid = queryjson["ProblemId"].asString();

    std::string problemcache = ReDB::GetInstance()->GetProblemCache(problemid);

    Json::Reader reader;
    Json::Value resjson;

    //取到redis缓存
    if (problemcache != "")
    {
        reader.parse(problemcache, resjson);
        return resjson;
    }

    //没有取到redis缓存，从mongodb中查
    resjson = MoDB::GetInstance()->SelectProblem(queryjson);

    if (resjson["Result"].asString() == "Success")
    {
        ReDB::GetInstance()->AddProblemCache(problemid, resjson.toStyledString());
    }

    return resjson;
}

Json::Value ProblemList::SelectProblemList(Json::Value queryjson)
{
    return MoDB::GetInstance()->SelectProblemList(queryjson);
}

Json::Value ProblemList::SelectProblemListByAdmin(Json::Value queryjson)
{
    return MoDB::GetInstance()->SelectProblemListByAdmin(queryjson);
}

bool GetTestInfoAndSPJ(Json::Value &resjson)
{
    std::string problemid = std::to_string(resjson["_id"].asInt64());
    int judgenum = stoi(resjson["JudgeNum"].asString());
    std::string DATAPATH = PROBLEMDATAPATH + problemid;
    std::ifstream ifilein, ifileout;

    for (int i = 0; i < judgenum; i++)
    {
        Json::Value value;
        std::string inpath = DATAPATH + "/" + std::to_string(i + 1) + ".in";
        std::string outpath = DATAPATH + "/" + std::to_string(i + 1) + ".out";

        ifilein.open(inpath);
        std::string instr{
            std::istreambuf_iterator<char>(ifilein),
            std::istreambuf_iterator<char>()
        };
        ifilein.close();

        ifileout.open(outpath);
        std::string outstr{
            std::istreambuf_iterator<char>(ifileout),
            std::istreambuf_iterator<char>()
        };
        ifileout.close();

        value["in"] = instr;
        value["out"] = outstr;
        resjson["TestInfo"].append(value);
    }

    resjson["IsSPJ"] = false;
    std::string spjpath = DATAPATH + '/' + "spj.cpp";
    //SPJ.cpp文件存在
    if (access(spjpath.data(),F_OK) == 0)
    {
        std::ifstream ifilespj;
        ifilespj.open(spjpath);
        std::string spjstr{
            std::istreambuf_iterator<char>(ifilespj),
            std::istreambuf_iterator<char>()
        };
        ifilespj.close();

        resjson["IsSPJ"] = true;
        resjson["SPJ"] = spjstr;
    }
    return true;
}

Json::Value ProblemList::SelectProblemInfoByAdmin(Json::Value queryjson)
{
    Json::Value resjson = MoDB::GetInstance()->SelectProblemInfoByAdmin(queryjson);
    //如果插入数据库失败
    if (resjson["Result"] == "Fail")
    {
        return resjson;
    }
    //获取测试点数据
    GetTestInfoAndSPJ(resjson);
    return resjson;
}

bool SaveTestInfoAndSPJ(Json::Value queryjson)
{
    //创建文件夹
    std::string DATAPATH = PROBLEMDATAPATH + std::to_string(queryjson["_id"].asInt64());
    std::string commend = "mkdir " + DATAPATH;
    system(commend.c_str());
    //向文件中写数据
    for (int i = 0; i < queryjson["JudgeNum"].asInt(); i++)
    {
        std::ofstream ofilein, ofileout;
        std::string inpath = DATAPATH + "/" + std::to_string(i + 1) + ".in";
        std::string outpath = DATAPATH + "/" + std::to_string(i + 1) + ".out";

        ofilein.open(inpath.c_str());
        std::cout << queryjson["TestInfo"][i]["in"].asString() << std::endl;
        ofilein << queryjson["TestInfo"][i]["in"].asString();
        ofilein.close();

        ofileout.open(outpath.c_str());
        ofileout << queryjson["TestInfo"][i]["out"].asString();
        ofileout.close();
    }
    //如果有SPJ文件，写入SPJ
    if (queryjson["IsSPJ"].asBool())
    {
        std::ofstream ofilespj;
        std::string spjpath = DATAPATH + "/spj.cpp";
        ofilespj.open(spjpath.data());
        ofilespj << queryjson["SPJ"].asString();
        ofilespj.close();
    }
    return true;
}

Json::Value ProblemList::InsertProblem(Json::Value queryjson)
{
    Json::Value resjson = MoDB::GetInstance()->InsertProblem(queryjson);
    //如果插入数据库失败
    if (resjson["Result"] == "Fail")
    {
        return resjson;
    }

    queryjson["_id"] = resjson["_id"];
    //保存测试点数据
    SaveTestInfoAndSPJ(queryjson);
    return resjson;
}

Json::Value ProblemList::UpdateProblem(Json::Value queryjson)
{
    Json::Value resjson = MoDB::GetInstance()->UpdateProblem(queryjson);
    //如果插入数据库失败
    if (resjson["Result"].asString() == "Fail")
    {
        return resjson;
    }

    queryjson["_id"] = resjson["_id"];
    //删除已有测试点文件
    std::string command = "rm -rf " + PROBLEMDATAPATH + std::to_string(queryjson["_id"].asInt());
    system(command.c_str());
    //保存测试点数据
    SaveTestInfoAndSPJ(queryjson);

    std::string problemid = queryjson["ProblemId"].asString();
    // 删除缓存
    ReDB::GetInstance()->DeleteProblemCache(problemid);

    return resjson;
}

Json::Value ProblemList::DeleteProblem(Json::Value queryjson)
{
    Json::Value resjson = MoDB::GetInstance()->DeleteProblem(queryjson);

    if (resjson["Result"] == "Fail")
        return resjson;

    // 删除数据
    std::string DATA_PATH = PROBLEMDATAPATH + queryjson["ProblemId"].asString();
    std::string command = "rm -rf " + DATA_PATH;

    system(command.data());

    // 删除缓存
    ReDB::GetInstance()->DeleteProblemCache(queryjson["ProblemId"].asString());

    return resjson;
}

bool ProblemList::UpdateProblemStatusNum(Json::Value queryjson)
{
    return MoDB::GetInstance()->UpdateProblemStatusNum(queryjson);
}
